import axios, { type AxiosRequestConfig, type AxiosResponse, type AxiosError } from 'axios';
import { ref, type Ref, type UnwrapRef } from 'vue';
import { cloneDeep } from 'lodash';

declare module 'axios' {
    interface AxiosRequestConfig {
        /**
         * 是否允许取消请求
         */
        abort?: boolean
        /**
         * 是否显示请求提示信息
         */
        toast?: boolean
    }
}

/***
 * HTTP请求方法类型定义
 * @typedef {'GET' | 'POST'} Methods
 * @description 支持的HTTP请求方法，目前仅包含GET和POST
 */
type Methods = 'GET' | 'POST'

/***
 * 请求配置接口
 * @interface RequestConfig
 * @description 定义请求的基本配置信息
 */
interface RequestConfig {
    /***
     * 请求URL地址
     */
    url: string;
    /***
     * HTTP请求方法，默认为GET
     */
    method?: Methods;
    /***
     * 请求参数
     */
    params?: Record<string, any>;
    /***
     * Axios额外配置选项
     */
    options?: AxiosRequestConfig;
}

/***
 * API响应数据接口
 * @interface ResponseData
 * @description 定义API返回的标准数据结构
 * @template T - 响应数据的类型
 */
interface ResponseData<T> {
    /**
     * 状态码
     */
	status: number
    /**
     * 提示信息
     */
	toast: string
    /**
     * 实际响应数据
     */
	data: T
    /**
     * 请求是否成功
     */
	success: boolean
}

async function request<T = any>(config: RequestConfig): Promise<T> {
    let { url, method = 'GET', params = {}, options = {} } = config;

    options =  {
        abort: true,
        toast: true,
        ...options
    };

    const axiosConfig: AxiosRequestConfig = {
        url,
        method,
        ...options,
        [method === 'GET' ? 'params' : 'data']: params
    };

    try {
        const response = await axios<T, AxiosResponse<ResponseData<T>>>(axiosConfig);
        options.toast && alert(response.data.toast);
        if (response.data.success) {
            return response.data.data;
        } else {
            return Promise.reject(response.data);
        }
    } catch (error) {
        const axiosError = error as AxiosError;
        console.error('请求失败:', axiosError.message);
        return Promise.reject(error);
    }
}

/***
 * useAxios Hook配置选项接口
 * @interface UseAxiosOptions
 * @description 定义useAxios Hook的配置选项，继承自RequestConfig
 * @template T - 请求响应数据的类型
 * @extends {RequestConfig}
 */
interface UseAxiosOptions<T = any> extends RequestConfig {
    /**
     * 是否立即执行请求，默认为true
     */
    immediate?: boolean;
    /**
     * 请求成功回调函数
     */
    onSuccess?: (data: T) => void;
    /**
     * 请求失败回调函数
     */
    onError?: (error: AxiosError) => void;
    /**
     * 请求完成回调函数（无论成功或失败）
     */
    onFinally?: () => void;
    /**
     * 请求前回调函数
     */
    onBefore?: (params: Record<string, any>) => Record<string, any>;
}

/***
 * useAxios Hook返回值接口
 * @interface UseAxiosReturn
 * @description 定义useAxios Hook的返回值结构
 * @template T - 请求响应数据的类型
 */
interface UseAxiosReturn<T> {
    /**
     * 请求加载状态
     */
    loading: Ref<boolean>;
    /**
     * 请求错误信息
     */
    error: Ref<AxiosError | null>;
    /**
     * 请求响应数据
     */
    data: Ref<T | null>;
    /**
     * 手动触发请求的方法
     */
    request: (config?: RequestConfig) => Promise<T>;
}

function useAxios<T = any>({
    url,
    method = 'GET',
    params = {},
    options = {},
    immediate = true,
    onSuccess,
    onError,
    onFinally,
    onBefore
}: UseAxiosOptions<T>): UseAxiosReturn<T> {
    const loading = ref(false);
    const error = ref<AxiosError | null>(null);
    const data = ref<T | null>(null);

    async function runasync (config?: RequestConfig) {
        loading.value = true;
        error.value = null;

        try {
            let onBeforeParams = onBefore && onBefore(cloneDeep(params));
            const finallyParams = config?.params || onBeforeParams || params
            const result = await request<T>({
                url: config?.url || url,
                method,
                params: finallyParams,
                options
            });
            data.value = result as UnwrapRef<T>;
            onSuccess && onSuccess(result);
            return result;
        } catch (err) {
            error.value = err as AxiosError;
            onError && onError(err as AxiosError);
            throw err;
        } finally {
            loading.value = false;
            onFinally && onFinally();
        }
    };

    if (immediate && url) {
        runasync();
    }

    return {
        loading,
        error,
        // @ts-ignore
        data,
        runasync
    };
}

const {data} = useAxios({
    url: '',
})

/***
 * 用户信息类型定义
 * @typedef {Object} User
 * @description 定义用户信息的数据结构
 */
type User = {
    /***
     * 用户ID
     */
    id: number;
    /***
     * 用户名
     */
    name: string;
    /***
     * 用户邮箱
     */
    email: string;
}

async function test() {
    const data = await request<User>({
        url: 'https://jsonplaceholder.typicode.com/users/1',
        method: 'GET',
        options: {
            toast: false,
        }
    });

    console.log(data);
}